iT邦幫忙

2018 iT 邦幫忙鐵人賽
DAY 3
4
Modern Web

邁向 JavaScript 勇者之路系列 第 3

JavaScript 變數的宣告與他的作用域

  • 分享至 

  • xImage
  •  

變數分為全域與區域變數,差異點在於宣告 (var) 的方式,就 MSDN 上的說明 在函式定義之外宣告的變數就是全域變數,其值可在整個程式中存取和修改。 所以我們可以使用函式來做兩個的分隔點,函式之內宣告的稱為區域,函式以外宣告的稱為全域

全域性的變數

在函數外宣告的變數則是具有全域性(或是包含全域物件之內),在瀏覽器下的全域物件是 window,有以下方式所產生的變數都會在 window 內。

// 在函示外宣告
var mom = '老媽';

// 沒有使用 var
mom = '老媽';

(function () {
  // 或是在函式內,但沒有使用 var
  mom = '老媽';
})();

以上方式都可以在 console.log(window); 後找到 `mom 這個變數,這個變數也屬於 全域物件,因此所有函式也都能取用此變數。

https://ithelp.ithome.com.tw/upload/images/20171206/20083608kbBpsa3wKj.png

另外,也可以直接產生在 window 物件下。

window.mom = '老媽';

這幾種方式都會在 window 物件下產生 mom,並且所有函示都能取用,但還是有些差異 (後面會介紹),但就實際使用來說,建議無論如何都宣告你的變數

變數與他的作用域

每個變數在宣告時,都只會在執行環境內建立記憶體,這個就是他的作用域,單如果此作用域內沒有可用的變數時,他則會參照外圍的。

function doMorningWork() {
  var mom = "老媽";

  function sayHi() {
	  var greeting = 'hi';
    return greeting + ' ' + mom;
  }
  console.log(sayHi());
}
doMorningWork();   // 執行

回到上一集的故事:
小明會將每一天的要做的事情寫在記事本內,並且記錄著許多工作內容。小明在 doMorningWork() 工作下建立了 mom 變數,這個 mom 就僅屬於 doMorningWork() 內,其它外部的函式都無法取用這個函式。 (旁白:小明出門後就可以不認這個媽媽了!?)

https://ithelp.ithome.com.tw/upload/images/20171206/20083608iAiKw3Q0bZ.jpg

  • 外層 doMorningWork(); 具有 mom 的變數
    • 內層 sayHi(); 可以使用 mom 這個變數,讓小明可以跟媽媽說早安
  • 另一個函式就無法取用 mom 這個變數。

其中內層沒有 mom 的變數,他就會向外層尋找,找到有相同名稱的就直接拿來使用。(旁白:小明啊,你應該把媽設為全域啊!?)

變數與記憶體關係

使用 var 宣告一個變數時,記憶體會先準備一個空間給予此變數,所以在實際運行前調用此變數並不會出現錯誤,只會出現 undefined (已經有記憶體空間,但沒有值)。

console.log(mom); // undefined
var mom = '老媽';

故事:
小明本身記性就不好,他會採取先整個看一次的方式,將整個印象存在腦中 (開啟記憶體空間),實際開始後再把實際把當天人、事、物整個記在腦內。

宣告與不宣告

MDN 文中提到 其中差異在於, 已宣告的變數是全域物件裡的一個無法變更 (non-configurable) 的屬性, 而未宣告的變數則是可變更的 (configurable) ,可以嘗試刪除產生的變數,觀察其差異。

案例:

var mom1 = "老媽1";
mom2 = "老媽2"; 

(function () {
  mom3 = "老媽3"; 
})();

delete mom1;
delete mom2;
delete mom3;

console.log(window.mom1);  // 僅剩此有值
console.log(window.mom2);
console.log(window.mom3); 

提醒

如果使用 var 則會先在記憶體準備一個空間給他,所以執行以前使用這個變數還不至於跳錯。

console.log(mom); // undefined
var mom = '老媽';

但如果沒有使用 var,則會跳出錯誤。

console.log(mom); // mom is not defined
mom = '老媽';

所以無論你的變數或函式是否要使用全域,都盡可能地去宣告它。至於 LetConst 請容許我到後面 ES6 章節再來介紹它 :)。

文章同時發表於:https://wcc723.github.io/javascript/2017/12/06/javascript-variables/


上一篇
JavaScript 執行環境與堆疊
下一篇
一次只能做一件事情的 JavaScript,解釋 Event queue 怎能不用動畫呢
系列文
邁向 JavaScript 勇者之路30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
yuski
iT邦新手 4 級 ‧ 2017-12-10 14:30:41

終於知道undefined是甚麼意思
有時跑程式在console log都會出現
感謝老師的文章!!!

卡斯伯 iT邦研究生 1 級 ‧ 2017-12-11 09:22:41 檢舉

/images/emoticon/emoticon30.gif

我要留言

立即登入留言